import {Worksheet} from 'exceljs'

/**
 * 列的枚举类型定义
 */
export interface ColumnEnum {
  new(label: string, value?: any): ColumnEnum
}

enum ColumnTypes {
  /**
   * 字符串类型
   */
  STRING = 'string',

  /**
   * 数值类型
   */
  NUMBER = 'number',

  /**
   * 日期类型
   */
  DATE = 'date',

  /**
   * 日期时间类型
   */
  DATETIME = 'DATETIME'
}

export type ColumnWriterCallbackArgs = {
  value: any,
  // eslint-disable-next-line no-use-before-define
  column: ColumnDef
}
export type ColumnReaderCallbackArgs = {
  value: any,
  // eslint-disable-next-line no-use-before-define
  column: ColumnDef
}

export type ColumnWriteCallback = (arg: ColumnWriterCallbackArgs) => any;
export type ColumnReadCallback = (arg: ColumnReaderCallbackArgs) => any;

/**
 * 单元格样式
 */
export type CellStyle = {
  /**
   * 宽度，不指定时为默认宽度
   */
  width: number,
  /**
   * 文本颜色，不指定时为默认值。格式为： argb
   */
  color: number,
  /**
   * 是否使用粗体，默认为： 表头=true，值=false
   */
  bold: boolean,
  /**
   * 文字大小
   */
  size: number,
  /**
   * 是否使用斜体
   */
  italic: boolean,
}

/**
 * 指明操作是读取还是写入
 */
export type IO_TYPES = 'i' | 'o';

/**
 * 自定义枚举无效时的处理函数
 * @param {Object} data 数据
 * @param {any} data.value 当前的枚举值
 * @param {ColumnDef} data.column 当前的列定义
 * @param {IO_TYPES} io 当前的IO类型，i 表示读取数据，o 表示写入数据
 * @return 返回的值将作为枚举的最终值
 */
export type InvalidEnumHandler = (data: { value: any, column: ColumnDef }, io: IO_TYPES) => any;

export type ColumnDefOptions = {
  /**
   * 列是否必填的。当其为 true 时，其值不能为空
   */
  required: boolean;
  type: ColumnTypes;
  enums: ColumnEnum[];
  headerStyle: CellStyle;
  writeParser: ColumnWriteCallback;
  readParser: ColumnReadCallback;
  /**
   * 留空表示不允许无效值; 设置为 i 表示允许读取无效值; 设置为 o 表示允许写入无效值; 设置 io 允许读写无效值; 设置为函数表示自定义处理，函数返回处理后的值
   */
  invalidEnum: string | InvalidEnumHandler;
  help: string;
}

/**
 * 列定义
 */
export interface ColumnDef {

  new(name: string, field: string, options?: ColumnDefOptions): ColumnDef;

  /**
   * 处理导入时的数据
   */
  parseReadValue(value: any): any;

  /**
   * 处理导出时的数据
   */
  parseWriteValue(value: any, row: (Object | any[])): any;

  getEnumLabels(): string[];

  /**
   * 获取此表的表头注释
   */
  getHeaderComment(): string;

  getHelp(): string[];

  /**
   * 列数据的类型
   */
  types: ColumnTypes;

  name: string;

  field: string;

  options: ColumnDefOptions;
}

export type SheetRowHandlerCallbackOption = {
  data: Object,
  raw: Object,
  index: number
}

export type SheetRowHandlerCallback = (arg: SheetRowHandlerCallbackOption) => any;

export type SheetDefOptions = {
  rowHandler: SheetRowHandlerCallback,
  /**
   * 最多读取的数据行数
   */
  maxRowCount: number,
  /**
   * 用于描述如何填写的帮助信息，此信息会汇集到帮助表中
   */
  help: string;
}

export type SheetInfo = {
  name: string,
  rows: any[][]
}

/**
 * 表定义
 */
export interface SheetDef {

  new(name: string, columns: ColumnDef[], options?: SheetDefOptions): SheetDef;

  /**
   */
  read(sheet: Worksheet): SheetInfo;

  /**
   * 将数据处理成可以写入 sheet 的数组
   */
  write(data: (Object[] | any[][]), withHelp: boolean): Object[];

  getHelp(): string[][];

  name: string;

  /**
   * @type {ColumnDef[]}
   */
  columns: ColumnDef[];

  options: SheetDefOptions
}

export type HelpSheetOptionOptions = {

  sheetName: string;

  title: string;

  sheetIndex: number;
}

/**
 * 帮助表选项
 */
export interface HelpSheetOption {

  // eslint-disable-next-line no-useless-constructor
  new(help?: string, options?: HelpSheetOptionOptions): HelpSheetOption;

  help: string;

  sheetName: string;

  title: string;

  sheetIndex: number;
}

/**
 * 工作薄定义
 */
export interface WorkbookDef {

  new(sheets: Array<SheetDef>, helpSheetOption?: HelpSheetOption): WorkbookDef;

  /**
   * 读取文件内容
   */
  readFile(file: any): Promise<ArrayBuffer>;

  /**
   * 从 文件对象 读取数据
   */
  read(file: File): Promise<SheetInfo[]>;

  /**
   * 将数据写入文件
   */
  write(data: SheetInfo[], saveAs: string, withHelp?: boolean): Promise<Blob | undefined>;

  /**
   * 将数据写入文件的第一个表
   */
  writeFirst(rows: (Object[] | any[][]), saveAs: string, withHelp?: boolean): Promise<Blob | undefined>;
}
